/**
 * 项目名：	Rumba Plan
 * 
 * 版权所有(C)，上海海鼎信息工程股份有限公司，2007，所有权利保留。
 * 
 * 文件名：	DataPacket.java
 * 模块说明：	
 * 修改历史：
 * Jun 8, 2007 - zhangyanbo - 创建。
 */
package com.hd123.rumba.report;

import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 数据包构造器
 * <p>
 * 
 * 提供报表所属数据包的构造。
 * 
 * @author zhangyanbo
 * 
 */
public class DataPacketBuilder {

  private TableDef def;
  private TableData data;
  private OutputStream os;
  public static SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss000");

  private DataPacketBuilder() {
    super();
  }

  public static DataPacketBuilder getBuilder(OutputStream os) {
    DataPacketBuilder builder = new DataPacketBuilder();
    builder.os = os;
    builder.def = new TableDef();
    builder.data = new TableData(builder.def);
    return builder;
  }

  public TableData getTableData() {
    return data;
  }

  public TableDef getTableDef() {
    return def;
  }

  public OutputStream getOutputStream() {
    return os;
  }

  private void buildHeader() throws Exception {
    os.write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>".getBytes());
  }

  private void writeMetadata(StringBuffer sb, TableDef def) throws Exception {
    sb.append("<FIELDS>");
    for (int i = 0; i < def.getFields().size(); i++) {
      Field f = def.getFields().get(i);
      sb.append("<FIELD attrname=\"" + f.getName() + "\"");
      if (f.getFieldType() == Field.NESTED) {
        sb.append(" fieldtype=\"nested\">");
        writeMetadata(sb, def.getTableDef(f.getName()));
        sb.append("</FIELD>");
      } else {
        if (f.getFieldType() == Field.STRING) {
          sb.append(" fieldtype=\"string\"");
          sb.append(" width=\"" + f.getWidth() + "\"");
        } else if (f.getFieldType() == Field.INTEGER) {
          sb.append(" fieldtype=\"fixed\"");
          sb.append(" width=\"" + f.getWidth() + "\"");
        } else if (f.getFieldType() == Field.DECIMAL) {
          sb.append(" fieldtype=\"fixedFMT\"");
          sb.append(" width=\"" + f.getWidth() + "\"");
          sb.append(" decimals=\"" + f.getDecimals() + "\"");
        } else if (f.getFieldType() == Field.DATETIME) {
          sb.append(" fieldtype=\"SQLdateTime\"");
        } else
          throw new Exception("无法识别的字段类型：" + f.getFieldType());
        if (f.isRequired())
          sb.append(" required=\"true\"");
        sb.append("/>");
      }
    }
    sb.append("</FIELDS>");
  }

  private void buildMetadata() throws Exception {
    os.write("<DATAPACKET Version=\"2.0\">".getBytes("utf-8"));
    StringBuffer sb = new StringBuffer();
    sb.append("<METADATA>");
    writeMetadata(sb, def);
    sb.append("</METADATA>");
    os.write(sb.toString().getBytes("utf-8"));
  }

  private void writeRowData(StringBuffer sb, TableData table) throws Exception {
    for (int i = 0; i < table.getRecords().size(); i++) {
      Object[] r = table.getRecords().get(i);
      String tag = "ROW";
      if (table.getTableDef().getParent() != null)
        tag = tag + table.getTableDef().getName();
      sb.append("<" + tag);
      Field f = null;
      boolean b = true;
      for (int j = 0; j < r.length; j++) {
        f = table.getTableDef().getFields().get(j);
        if (r[j] != null) {
          if (f.getFieldType() == Field.NESTED) {
            if (b) {
              sb.append(">");
              b = false;
            }
            sb.append("<" + f.getName() + ">");
            writeRowData(sb, (TableData) r[j]);
            sb.append("</" + f.getName() + ">");
          } else {
            if (f.getFieldType() == Field.STRING || f.getFieldType() == Field.INTEGER
                || f.getFieldType() == Field.DECIMAL)
              sb.append(" " + f.getName() + "=\"" + r[j] + "\"");
            else if (f.getFieldType() == Field.DATETIME)
              sb.append(" " + f.getName() + "=\"" + sdf.format((Date) r[j]) + "\"");
          }
        }
      }
      if (b)
        sb.append("/>");
      else
        sb.append("</" + tag + ">");
    }
  }

  private void buildRowData() throws Exception {
    StringBuffer sb = new StringBuffer();
    sb.append("<ROWDATA>");
    writeRowData(sb, data);
    sb.append("</ROWDATA>");
    os.write(sb.toString().getBytes("utf-8"));
    os.write("</DATAPACKET>".getBytes("utf-8"));
  }

  public void build() throws Exception {
    buildHeader();
    buildMetadata();
    buildRowData();
  }
}
